//
// Created on 2022/9/23.
//

#include <js_native_api.h>
#include <js_native_api_types.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>

#include "NapiTest.h"

napi_ref NapiTest::sConstructor_ = nullptr;
std::string NapiTest::_msg="";

NapiTest::~NapiTest()
{
    // 是否有创建生命周期，有的话释放
    if (mRef != nullptr) {
        napi_delete_reference(mEnv, mRef);
    }
}

napi_value NapiTest::SetMsg(napi_env env, napi_callback_info info) {
    napi_value result = nullptr;
    napi_get_undefined(env, &result);
    char msg[128] = {0};

    napi_value msgvalue;
    size_t argc = 1, size = 0;

    if (napi_get_cb_info(env, info, &argc, &msgvalue, nullptr, nullptr) != napi_ok) {
        return result;
    }

    if (napi_get_value_string_utf8(env, msgvalue, msg, sizeof(msg), &size) != napi_ok) {
        return result;
    }
    
    _msg = msg;
    
    return result;
}

napi_value NapiTest::GetMsg(napi_env env, napi_callback_info info) { 
    napi_value result = nullptr;
    char *msg= "hello NapiTest";
    
    napi_get_undefined(env, &result);
    
    if (_msg.length() > 0) {
        msg = (char *)(_msg.c_str());
    }
    
    if (napi_create_string_utf8(env, msg, strlen(msg), &result) != napi_ok) {
        return result;
    }
    
    return result;
}

napi_value NapiTest::Create(napi_env env, napi_callback_info info) {
    napi_status status;
    napi_value constructor = nullptr, result = nullptr;
    // 获取生命周期变量
    status = napi_get_reference_value(env, sConstructor_, &constructor);

    // 创建生命周期内的对象并将其返回
    status = napi_new_instance(env, constructor, 0, nullptr, &result);
    auto napiTest = new NapiTest();
    // 绑定实例类napiTest到导出的对象result
    if (napi_wrap(env, result, reinterpret_cast<void *>(napiTest), Destructor, nullptr, &(napiTest->mRef)) == napi_ok) {
        return result;
    }
    
    return nullptr;
}

napi_value NapiTest::Constructor(napi_env env, napi_callback_info info)
{
    napi_value undefineVar = nullptr, thisVar = nullptr;
    napi_get_undefined(env, &undefineVar);

    // 获取传入的参数对象，对象不为空，根据该参数创建实例并并绑定到该对象
    if (napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr) == napi_ok && thisVar != nullptr) {

        // 创建NapiTest 实例
        NapiTest *reference = new NapiTest(env);

        // 绑定实例到对象并获取对象的生命周期
        if (napi_wrap(env, thisVar, reinterpret_cast<void *>(reference), NapiTest::Destructor, nullptr, &(reference->mRef)) == napi_ok) {
            return thisVar;
        }

        return thisVar;
    }
    
    return undefineVar;
}

void NapiTest::Destructor(napi_env env, void *nativeObject, void *finalize)
{
    // 释放资源
    NapiTest *test = reinterpret_cast<NapiTest*>(nativeObject);
    test->~NapiTest();
}

napi_value NapiTest::Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        { "getMsg", nullptr, NapiTest::GetMsg, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "setMsg", nullptr, NapiTest::SetMsg, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "create", nullptr, NapiTest::Create, nullptr, nullptr, nullptr, napi_default, nullptr }
    };

    napi_value constructor = nullptr;

    // 定义 JS的类
    if (napi_define_class(env, NAPI_CLASS_NAME, NAPI_AUTO_LENGTH, Constructor, nullptr, sizeof(desc) / sizeof(desc[0]),
                          desc, &constructor) != napi_ok) {
        return nullptr;
    }

    // 创建生命周期，初始引用计数设为1
    if (napi_create_reference(env, constructor, 1, &sConstructor_) != napi_ok) {
        return nullptr;
    }

    // 设置NapiTest对象相关属性并绑定到导出变量exports
    if (napi_set_named_property(env, exports, NAPI_CLASS_NAME, constructor) != napi_ok) {
        return nullptr;
    }

    // 返回已经绑定对应导出类对象的值
    return exports;
}
